package com.basker.pisces.utils;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;

import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * @author hangwen
 * @date 2020/12/2
 */
public abstract class ListsUtils {

    /**
     * 将Collection里的元素转义后，以List返回
     */
    public static <T, R> List<R> map(final Collection<T> list, final Function<T, R> mapper) {
        return doIndexMap(list, (item, index) -> mapper.apply(item), false, true);
    }

    /**
     * 将Collection里的元素转义后，以List返回，但是会过滤掉转义为null的元素
     */
    public static <T, R> List<R> mapNotNull(final Collection<T> list, final Function<T, R> mapper) {
        return doIndexMap(list, (item, index) -> mapper.apply(item), false, false);
    }

    /**
     * 将Collection构建成一个Map，如果已经存在相同的key则覆盖前者,value即元素自身
     */
    public static <T, K> Map<K, T> toMap(final Collection<T> list,
                                         final Function<T, K> keyMapper) {
        return toMap(list, keyMapper, v -> v);
    }

    /**
     * 将Collection构建成一个Map，如果已经存在相同的key则覆盖前者
     */
    public static <T, K, V> Map<K, V> toMap(final Collection<T> list,
                                            final Function<T, K> keyMapper,
                                            final Function<T, V> valueMapper) {
        if (CollectionUtils.isEmpty(list)) {
            return Maps.newLinkedHashMap();
        }

        HashMap<K, V> hashMap = Maps.newLinkedHashMapWithExpectedSize(list.size());

        list.forEach(item -> {
            K key = keyMapper.apply(item);
            if (key != null) {
                hashMap.put(key, valueMapper.apply(item));
            }
        });

        return hashMap;
    }

    private static <T, R> List<R> doIndexMap(final Collection<T> list,
                                             final BiFunction<T, Integer, R> mapper,
                                             final boolean skipNull,
                                             final boolean exportNull) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }

        List<R> result = Lists.newArrayListWithExpectedSize(list.size());

        int index = 0;
        for (T item : list) {
            if (skipNull && item == null) {
                index++;
                continue;
            }

            R mappedItem = mapper.apply(item, index);
            if (!exportNull && mappedItem == null) {
                index++;
                continue;
            }

            result.add(mappedItem);
            index++;
        }

        return result;
    }
}
